package protocol

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"gitee.com/hexug/devcloud/maudit/apps"
	"gitee.com/hexug/devcloud/maudit/common/logger"
	"gitee.com/hexug/devcloud/maudit/conf"
	"gitee.com/hexug/devcloud/maudit/swagger"
	"gitee.com/hexug/devcloud/mcenter/apps/endpoint"
	"gitee.com/hexug/devcloud/mcenter/client/middleware/auth"
	"gitee.com/hexug/devcloud/mcenter/client/rpc"
	restfulspec "github.com/emicklei/go-restful-openapi/v2"
	"github.com/emicklei/go-restful/v3"
)

func NewHTTPService() *HTTPService {
	r := restful.DefaultContainer
	// 跨域中间件
	cors := restful.CrossOriginResourceSharing{
		AllowedHeaders: []string{"*"},
		AllowedDomains: []string{"*"},
		AllowedMethods: []string{"HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE"},
		CookiesAllowed: false,
		Container:      r,
	}
	// 将跨域中间件装载到容器中
	r.Filter(cors.Filter)
	cof := rpc.NewConfig()
	cof.ClientId = conf.C().GetString("mcenter.client_id")
	cof.ClientSecret = conf.C().GetString("mcenter.client_secret")
	cof.Address = conf.C().GetString("mcenter.addr")
	cof.ServerID = conf.C().GetString("server.server_id")
	//传入server_id
	rpcC, err := rpc.NewClient(cof)
	if err != nil {
		panic(err)
	}
	// fmt.Println(rpcC)
	// fmt.Printf("%s:%d\n", conf.C().Get("grpc.host"), conf.C().Get("grpc.port"))
	// fmt.Println(auth.NewHttpAuther(rpcC).FilterFunc)
	//调用中间件
	r.Filter(auth.NewHttpAuther(rpcC).AuthFunc)
	server := &http.Server{
		ReadHeaderTimeout: 60 * time.Second,
		ReadTimeout:       60 * time.Second,
		WriteTimeout:      60 * time.Second,
		IdleTimeout:       60 * time.Second,
		MaxHeaderBytes:    1 << 20, // 1M
		Addr:              fmt.Sprintf("%s:%d", conf.C().Get("http.host"), conf.C().Get("http.port")),
		Handler:           r,
	}

	return &HTTPService{
		Container: r,
		server:    server,
	}
}

// HTTPService http服务
type HTTPService struct {
	Container *restful.Container
	server    *http.Server
}

// mpaas/api/tokens/v1
// mpaas/api/users/v1
func (s *HTTPService) PathPrefix() string {
	return fmt.Sprintf("/%s/api", "mpaas")
}

// Start 启动服务
func (s *HTTPService) Start() error {
	//初始化挂载路由
	apps.InitHttp(s.PathPrefix(), s.Container)

	//注册服务的功能到mcenter
	wss := s.Container.RegisteredWebServices()
	var es *endpoint.RegisterRequest
	for _, ws := range wss {
		rts := ws.Routes()
		if len(rts) > 0 {
			es = endpoint.NewRegisterRequest()
			for _, r := range rts {
				cer := endpoint.NewCreateEndpointRequest()
				cer.Method = r.Method
				cer.Operation = r.Operation
				cer.Path = r.Path
				isAuth := r.Metadata["auth"]
				isPerm := r.Metadata["perm"]
				if isAuth != nil && isAuth.(bool) {
					cer.Auth = isAuth.(bool)
				}
				if isPerm != nil && isPerm.(bool) {
					cer.Perm = isPerm.(bool)
				}
				cer.ServiceId = conf.C().GetString("server.server_id")
				es.Items = append(es.Items, cer)
			}
		}
	}
	//注册endpoint
	cnf := rpc.NewConfig()
	cnf.Address = conf.C().GetString("mcenter.addr")
	cnf.ClientId = conf.C().GetString("mcenter.client_id")
	cnf.ClientSecret = conf.C().GetString("mcenter.client_secret")
	cs, err := rpc.NewClient(cnf)
	if err != nil {
		return err
	}
	if es != nil {
		_, err = cs.Endpoint().RegisterEndpoint(context.Background(), es)
		if err != nil {
			logger.L().Panic(err.Error())
		}
	}
	//注册完成
	//##################################################################

	// 装置子服务路由
	//配置API的swagger文档
	config := restfulspec.Config{
		// api列表是根据这个restful WebServices列表构建的。
		WebServices: restful.RegisteredWebServices(), //可以控制哪些服务是可见的
		//配置产生swagger文档的路径
		APIPath: "/apidocs.json",
		//[可选]如果设置，则使用生成的Swagger对象调用此函数
		PostBuildSwaggerObjectHandler: swagger.Docs,
		//指定根据name处理  这里处理state sizeCache  unknownFields三个name，这三个name是proto中字段，不是有效字段，需要忽略掉
		DefinitionNameHandler: func(name string) string {
			if name == "state" || name == "sizeCache" || name == "unknownFields" {
				return ""
			}
			return name
		},
	}
	//将swagger相关的配置装载到容器中
	//注意，所有路由的加载一定是要在装载swagger配置之前
	s.Container.Add(restfulspec.NewOpenAPIService(config))
	logger.L().Infof("Get the API using http://%s:%d%s", conf.C().Get("http.host"), conf.C().Get("http.port"), config.APIPath)

	// 启动 HTTP服务
	logger.L().Infof("HTTP服务启动成功, 监听地址: %s", s.server.Addr)
	if err := s.server.ListenAndServe(); err != nil {
		if err == http.ErrServerClosed {
			logger.L().Infof("Http服务已经停止了")
		}
		return fmt.Errorf("启动服务出错, %s", err.Error())
	}
	return nil
}

// Stop 停止server
func (s *HTTPService) Stop() error {
	logger.L().Info("开始关闭HTTP服务")
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	// 优雅关闭HTTP服务
	if err := s.server.Shutdown(ctx); err != nil {
		logger.L().Error("HTTP关闭服务超时, 强制退出")
	}
	return nil
}
